import { z } from "zod";
import { yunxiaoRequest, buildUrl } from "../../common/utils.js";
import { ChangeRequestSchema, PatchSetSchema } from "../../common/types.js";
import { handleRepositoryIdEncoding, floatToIntString } from "./utils.js";

// Schema definitions
export const GetChangeRequestSchema = z.object({
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
  repositoryId: z.string().describe("Repository ID or a combination of organization ID and repository name, for example: 2835387 or organizationId%2Frepo-name (Note: slashes need to be URL encoded as %2F)"),
  localId: z.string().describe("Local ID, represents the nth merge request in the repository"),
});

export const ListChangeRequestsSchema = z.object({
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
  page: z.number().int().default(1).optional().describe("Page number"),
  perPage: z.number().int().default(20).optional().describe("Items per page"),
  projectIds: z.string().nullable().optional().describe("Repository ID or a combination of organization ID and repository name list, for example: 2835387 or organizationId%2Frepo-name (Note: slashes need to be URL encoded as %2F), multiple separated by commas"),
  authorIds: z.string().nullable().optional().describe("Creator user ID list, multiple separated by commas"),
  reviewerIds: z.string().nullable().optional().describe("Reviewer user ID list, multiple separated by commas"),
  state: z.string().nullable().optional().describe("Merge request filter status. Possible values: opened, merged, closed. Default is null, which queries all statuses"),
  search: z.string().nullable().optional().describe("Title keyword search"),
  orderBy: z.string().default("updated_at").optional().describe("Sort field. Possible values: created_at (creation time), updated_at (update time, default)"),
  sort: z.string().default("desc").optional().describe("Sort order. Possible values: asc (ascending), desc (descending, default)"),
  createdBefore: z.string().nullable().optional().describe("Start creation time, time format is ISO 8601, for example: 2019-03-15T08:00:00Z"),
  createdAfter: z.string().nullable().optional().describe("End creation time, time format is ISO 8601, for example: 2019-03-15T08:00:00Z"),
});

export const ListChangeRequestPatchSetsSchema = z.object({
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
  repositoryId: z.string().describe("Repository ID or a combination of organization ID and repository name, for example: 2835387 or organizationId%2Frepo-name (Note: slashes need to be URL encoded as %2F)"),
  localId: z.string().describe("Local ID, represents the nth merge request in the repository"),
});

export const CreateChangeRequestSchema = z.object({
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
  repositoryId: z.string().describe("Repository ID or a combination of organization ID and repository name, for example: 2835387 or organizationId%2Frepo-name (Note: slashes need to be URL encoded as %2F)"),
  title: z.string().describe("Title, no more than 256 characters"),
  description: z.string().nullable().optional().describe("Description, no more than 10000 characters"),
  sourceBranch: z.string().describe("Source branch name"),
  sourceProjectId: z.number().optional().describe("Source repository ID (if not provided, will try to get automatically)"),
  targetBranch: z.string().describe("Target branch name"),
  targetProjectId: z.number().optional().describe("Target repository ID (if not provided, will try to get automatically)"),
  reviewerUserIds: z.array(z.string()).nullable().optional().describe("Reviewer user ID list"),
  workItemIds: z.array(z.string()).nullable().optional().describe("Associated work item ID list"),
  createFrom: z.string().optional().default("WEB").describe("Creation source. Possible values: WEB (created from web page), COMMAND_LINE (created from command line). Default is WEB"),
});

// Type exports
export type GetChangeRequestOptions = z.infer<typeof GetChangeRequestSchema>;
export type ListChangeRequestsOptions = z.infer<typeof ListChangeRequestsSchema>;
export type ListChangeRequestPatchSetsOptions = z.infer<typeof ListChangeRequestPatchSetsSchema>;
export type CreateChangeRequestOptions = z.infer<typeof CreateChangeRequestSchema>;

// 通过API获取仓库的数字ID
async function getRepositoryNumericId(organizationId: string, repositoryId: string): Promise<string> {
  const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${repositoryId}`;
  
  const response = await yunxiaoRequest(url, {
    method: "GET",
  });
  
  if (!response || typeof response !== 'object' || !('id' in response)) {
    throw new Error("Failed to get repository ID");
  }
  
  const repoId = response.id;
  if (!repoId) {
    throw new Error("Could not get repository ID");
  }
  
  return repoId.toString();
}

// Function implementations
export async function getChangeRequestFunc(
  organizationId: string,
  repositoryId: string,
  localId: string
): Promise<z.infer<typeof ChangeRequestSchema>> {
  const encodedRepoId = handleRepositoryIdEncoding(repositoryId);

  const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${encodedRepoId}/changeRequests/${localId}`;

  const response = await yunxiaoRequest(url, {
    method: "GET",
  });

  return ChangeRequestSchema.parse(response);
}

export async function listChangeRequestsFunc(
  organizationId: string,
  page?: number,
  perPage?: number,
  projectIds?: string,
  authorIds?: string,
  reviewerIds?: string,
  state?: string, // Possible values: opened, merged, closed
  search?: string,
  orderBy?: string, // Possible values: created_at, updated_at
  sort?: string, // Possible values: asc, desc
  createdBefore?: string,
  createdAfter?: string
): Promise<z.infer<typeof ChangeRequestSchema>[]> {
  const baseUrl = `/oapi/v1/codeup/organizations/${organizationId}/changeRequests`;
  
  // 构建查询参数
  const queryParams: Record<string, string | number | undefined> = {};
  
  if (page !== undefined) {
    queryParams.page = page;
  }
  
  if (perPage !== undefined) {
    queryParams.perPage = perPage;
  }
  
  if (projectIds !== undefined) {
    queryParams.projectIds = projectIds;
  }
  
  if (authorIds !== undefined) {
    queryParams.authorIds = authorIds;
  }
  
  if (reviewerIds !== undefined) {
    queryParams.reviewerIds = reviewerIds;
  }
  
  if (state !== undefined) {
    queryParams.state = state;
  }
  
  if (search !== undefined) {
    queryParams.search = search;
  }
  
  if (orderBy !== undefined) {
    queryParams.orderBy = orderBy;
  }
  
  if (sort !== undefined) {
    queryParams.sort = sort;
  }
  
  if (createdBefore !== undefined) {
    queryParams.createdBefore = createdBefore;
  }
  
  if (createdAfter !== undefined) {
    queryParams.createdAfter = createdAfter;
  }

  // 使用buildUrl函数构建包含查询参数的URL
  const url = buildUrl(baseUrl, queryParams);

  const response = await yunxiaoRequest(url, {
    method: "GET",
  });

  // 确保响应是数组
  if (!Array.isArray(response)) {
    return [];
  }

  // 解析每个变更请求对象
  return response.map(changeRequest => ChangeRequestSchema.parse(changeRequest));
}

export async function listChangeRequestPatchSetsFunc(
  organizationId: string,
  repositoryId: string,
  localId: string
): Promise<z.infer<typeof PatchSetSchema>[]> {
  const encodedRepoId = handleRepositoryIdEncoding(repositoryId);

  const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${encodedRepoId}/changeRequests/${localId}/diffs/patches`;

  const response = await yunxiaoRequest(url, {
    method: "GET",
  });

  // 确保响应是数组
  if (!Array.isArray(response)) {
    return [];
  }

  // 解析每个版本对象
  return response.map(patchSet => PatchSetSchema.parse(patchSet));
}

export async function createChangeRequestFunc(
  organizationId: string,
  repositoryId: string,
  title: string,
  sourceBranch: string,
  targetBranch: string,
  description?: string,
  sourceProjectId?: number,
  targetProjectId?: number,
  reviewerUserIds?: string[],
  workItemIds?: string[],
  createFrom: string = "WEB" // Possible values: WEB, COMMAND_LINE
): Promise<z.infer<typeof ChangeRequestSchema>> {
  const encodedRepoId = handleRepositoryIdEncoding(repositoryId);
  
  // 检查和获取sourceProjectId和targetProjectId
  let sourceIdString: string | undefined;
  let targetIdString: string | undefined;
  
  if (sourceProjectId !== undefined) {
    sourceIdString = floatToIntString(sourceProjectId);
  }
  
  if (targetProjectId !== undefined) {
    targetIdString = floatToIntString(targetProjectId);
  }
  
  // 如果repositoryId是纯数字，且sourceProjectId或targetProjectId未提供，直接使用repositoryId的值
  if (!isNaN(Number(repositoryId))) {
    // 是数字ID，可以直接使用
    if (sourceIdString === undefined) {
      sourceIdString = repositoryId;
    }
    if (targetIdString === undefined) {
      targetIdString = repositoryId;
    }
  } else if (repositoryId.includes("%2F") || repositoryId.includes("/")) {
    // 如果是组织ID与仓库名称的组合，调用API获取数字ID
    if (sourceIdString === undefined || targetIdString === undefined) {
      try {
        const numericId = await getRepositoryNumericId(organizationId, encodedRepoId);
        
        if (sourceIdString === undefined) {
          sourceIdString = numericId;
        }
        if (targetIdString === undefined) {
          targetIdString = numericId;
        }
      } catch (error) {
        throw new Error(`When using 'organizationId%2Frepo-name' format, you must first get the numeric ID of the repository and use it for sourceProjectId and targetProjectId parameters. Please use get_repository tool to get the numeric ID of '${repositoryId}' and then use that ID as the value for sourceProjectId and targetProjectId.`);
      }
    }
  }
  
  // 确保sourceProjectId和targetProjectId已设置
  if (sourceIdString === undefined) {
    throw new Error("Could not get sourceProjectId, please provide this parameter manually");
  }
  if (targetIdString === undefined) {
    throw new Error("Could not get targetProjectId, please provide this parameter manually");
  }
  
  const url = `/oapi/v1/codeup/organizations/${organizationId}/repositories/${encodedRepoId}/changeRequests`;
  
  // 准备payload
  const payload: Record<string, any> = {
    title: title,
    sourceBranch: sourceBranch,
    targetBranch: targetBranch,
    sourceProjectId: sourceIdString,
    targetProjectId: targetIdString,
    createFrom: createFrom,
  };
  
  // 添加可选参数
  if (description !== undefined) {
    payload.description = description;
  }
  
  if (reviewerUserIds !== undefined) {
    payload.reviewerUserIds = reviewerUserIds;
  }
  
  if (workItemIds !== undefined) {
    payload.workItemIds = workItemIds;
  }
  
  const response = await yunxiaoRequest(url, {
    method: "POST",
    body: payload,
  });
  
  return ChangeRequestSchema.parse(response);
} 